package demo.java.util;

import com.alibaba.fastjson.JSONObject;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;

public class ArraysDemo {

    private static Logger logger = LoggerFactory.getLogger(ArraysDemo.class);

    @Test
    public void testLength() {
        int[] a = new int[0];
        System.out.println(a.length);
    }

    /**
     * 两个数组为同一对象时才equals
     */
    @Test
    public void testEquals() {
        String[] a = new String[]{"a", "b"};
        logger.info(a.getClass().toString());
        logger.info(a.getClass().toGenericString());
        String[] b = new String[]{"a", "b"};
        logger.info("a == b: {}; a.equals(b): {}", a == b, a.equals(b));
        b = a;
        logger.info("a == b: {}; a.equals(b): {}", a == b, a.equals(b));
    }

    /**
     * list里可以放null值
     */
    @Test
    public void testNull() {
        List<String> list = Arrays.asList(null);
        System.out.println(list.size() + ": " + list);
        list = Arrays.asList("q", null, "", null);
        for (String string : list) {
            System.out.println(string);
        }
        try {
            String[] strArray = null;
            Arrays.asList(strArray);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }

    }

    @Test
    public void test() {
        int[] intArray = new int[2];
        intArray[0] = 1;
        intArray[1] = 2;
        logger.info("{}", intArray);
        intArray = new int[]{3, 4, 5};
        logger.info("{}", intArray);

        Set<String>[] array = new Set[]{Collections.emptySet(), Collections.emptySet()};
        logger.info("{}", array);
    }

    /**
     * 先将两个有序数组合并，再对合并后的数组去重
     */
    @Test
    public void testDoubleSort() {
        int[] o = {1, 3, 5, 7, 9, 11, 11, 12};
        int[] t = {2, 4, 6, 8, 10, 11, 12};
        int[] th = sort(o, t);
        System.out.println(Arrays.toString(th));
        List<Integer> list = new ArrayList<>(th.length);
        for (int i = 0; i < th.length; i++) {
            int loc = th[i];
            int next = th[i + 1];
            list.add(loc);
            if (loc == next) {
                i++;
            }
        }
        System.out.println(Arrays.toString(list.toArray()));
        logger.info(JSONObject.toJSONString(list));
    }

    /**
     * 最快实现两个有序数组合并为一个有序数组
     *
     * @param one
     * @param two
     * @return
     */
    public static int[] sort(int[] one, int[] two) {
        int onesize = one.length;
        int twosize = two.length;
        int threesize = onesize + twosize;
        int[] three = new int[threesize];
        int i = 0;
        int j = 0;
        for (int t = 0; t < threesize; t++) {
            // 如果第一个数组比较完了，直接把第二个数组后面的数，排序到后面
            if (i >= onesize) {
                three[t] = two[j++];
                // 如果第二个数组比较完了，直接把第一个数组后面的数，排序到后面
            } else if (j >= twosize) {
                three[t] = one[i++];
            } else {
                if (one[i] <= two[j]) {
                    three[t] = one[i++];
                } else {
                    three[t] = two[j++];
                }
            }
        }
        return three;
    }

    @Test
    public void arrayCopyDemo() {
        char[] copyFrom = {'d', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd'};
        char[] copyTo = new char[7];

        System.arraycopy(copyFrom, 2, copyTo, 0, 7);
        System.out.println(new String(copyTo));

        char[] copyTo2 = Arrays.copyOfRange(copyFrom, 2, 9);
        System.out.println(new String(copyTo2));
    }

    @Test
    public void multiDimArrayDemo() {
        String[][] names = {{"Mr. ", "Mrs. ", "Ms. "}, {"Smith", "Jones"}};
        // Mr. Smith
        System.out.println(names[0][0] + names[1][0]);
        // Ms. Jones
        System.out.println(names[0][2] + names[1][1]);
    }

    @Test
    public void arrayDemo() {
        byte[] anArrayOfBytes;
        short[] anArrayOfShorts;
        long[] anArrayOfLongs;
        float[] anArrayOfFloats;
        // this form is discouraged
        float anArrayOfFloats2[];
        double[] anArrayOfDoubles;
        boolean[] anArrayOfBooleans;
        char[] anArrayOfChars;
        String[] anArrayOfStrings;
        int[] anotherArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};

        // declares an array of integers
        int[] anArray;

        // allocates memory for 10 integers
        anArray = new int[10];

        // initialize first element
        anArray[0] = 100;
        // initialize second element
        anArray[1] = 200;
        // and so forth
        anArray[2] = 300;
        anArray[3] = 400;
        anArray[4] = 500;
        anArray[5] = 600;
        anArray[6] = 700;
        anArray[7] = 800;
        anArray[8] = 900;
        anArray[9] = 1000;

        System.out.println("Element at index 0: " + anArray[0]);
        System.out.println("Element at index 1: " + anArray[1]);
        System.out.println("Element at index 2: " + anArray[2]);
        System.out.println("Element at index 3: " + anArray[3]);
        System.out.println("Element at index 4: " + anArray[4]);
        System.out.println("Element at index 5: " + anArray[5]);
        System.out.println("Element at index 6: " + anArray[6]);
        System.out.println("Element at index 7: " + anArray[7]);
        System.out.println("Element at index 8: " + anArray[8]);
        System.out.println("Element at index 9: " + anArray[9]);

        System.out.println(anArray.length);
    }

    /**
     * 折半查找法
     * <li>① 首先确定整个查找区间的中间位置 mid = （ left + right ）/2 。
     * <li>② 用待查关键字值与中间位置的关键字值进行比较； 若相等，则查找成功 ;若大于，则在后（右）半个区域继续进行折半查找;
     * 若小于，则在前（左）半个区域继续进行折半查找。
     * <li>③ 对确定的缩小区域再按折半公式，重复上述步骤。最后，得到结果：要么查找成功， 要么查找失败。折半查找的存储结构采用一维数组存放
     *
     * <p>
     * <br>
     * 优缺点：
     * <li>折半查找法的优点是比较次数少，查找速度快，平均性能好；
     * <li>其缺点是要求待查表为有序表，且插入删除困难。
     * <li>因此，折半查找方法适用于不经常变动而查找频繁的有序列表。
     */
    @Test
    public void binarySearch() {
        Integer[] array1 = {19, 20, 42, 150,};
        System.out.println(array1.length);
        int idx = Arrays.binarySearch(array1, 19);
        System.out.println(idx);
        int idx2 = binarySearch(array1, 0, array1.length - 1, 19);
        System.out.println(idx);
    }

    // Like public version, but without range checks.
    public static int binarySearch(Object[] a, int fromIndex, int toIndex, Object key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            Comparable midVal = (Comparable) a[mid];
            int cmp = midVal.compareTo(key);

            if (cmp < 0) {
                low = mid + 1;
            } else if (cmp > 0) {
                high = mid - 1;
            } else {
                return mid; // key found
            }
        }
        return -(low + 1); // key not found.
    }

    @Test
    public void listToArray() {
        List<Integer> list = Arrays.asList(0, 1, null);
        Integer[] array = list.toArray(new Integer[list.size() + 2]);
        System.out.println(Arrays.toString(array));
        array = list.toArray(new Integer[0]);
        System.out.println(Arrays.toString(array));
    }

    static void testArray(int... ids) {
        System.out.println(ids);
        System.out.println(Arrays.toString(ids));
        List<int[]> list = Arrays.asList(ids);
        list.forEach(System.out::println);

        System.out.println("原型数据的数组，数组对象作为参数");
        int[] array2 = {1, 2, 3, 4, 5};
        List<int[]> list2 = Arrays.asList(array2);
        list2.forEach(System.out::println);
        System.out.println("包装类型的数组，数组的每个对象作为参数");

        Integer[] array3 = {1, 2, 3, 4, 5};
        List<Integer> list3 = Arrays.asList(array3);
        String tmp = Arrays.toString(array3);
        System.out.println(tmp);
        System.out.println(tmp.substring(1, tmp.length() - 1));

        List<Integer> list4 = Arrays.asList(1, 2, 3);
        list4.forEach(System.out::println);
    }

}
